﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Workflow.Activities;
using System.Workflow.Runtime;
using CommonWFLibrary;
using System.IO;
using System.Threading;

namespace CommonWFLibraryTest
{
    /// <summary>
    /// Summary description for t_FilePersistence
    /// </summary>
    [TestClass]
    public class t_FilePersistence
    {
        public t_FilePersistence()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion


        /// <summary>
        /// This is what we use to test out some simple crap
        /// </summary>
        public class SimpleWorkflowWithIdle : SequentialWorkflowActivity
        {
            public SimpleWorkflowWithIdle()
            {
                InitializeComponent();
            }

            public void InitializeComponent()
            {
                this.CanModifyActivities = true;
                // set delay id and 10 second timeout
                this.delay = new DelayActivity();
                this.delay.Name = "delay";
                this.delay.TimeoutDuration = new TimeSpan(0, 0, 5);

                // add delay activity to workflow
                this.Activities.Add(this.delay);

                // set workflow name
                this.Name = "PersistenceServiceWorkflow";
                this.CanModifyActivities = false;
            }

            public DelayActivity delay;
        }

        [TestMethod]
        public void SimplePersistence()
        {
                    /// Make sure we spot the running!
            using (ManualResetEvent waitHandle = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    try
                    {
                        // Unload the workflow as soon as it is idle!
                        DirectoryInfo location = new DirectoryInfo(".\\bogusSimple");
                        Assert.IsFalse(location.Exists, "The directory location already exists before we run? Huh?");
                        workflowRuntime.AddService(new FilePersistenceService(true, location));

                        workflowRuntime.WorkflowCompleted += (o, arg) => waitHandle.Set();
                        workflowRuntime.WorkflowTerminated += (o, arg) => waitHandle.Set();
                        workflowRuntime.ServicesExceptionNotHandled += (o, arg) => waitHandle.Set();

                        workflowRuntime.StartRuntime();

                        workflowRuntime.CreateWorkflow(typeof(SimpleWorkflowWithIdle)).Start();

                        DateTime startup = DateTime.Now;
                        bool sawfiles = false;
                        while (((DateTime.Now - startup).Seconds < 7) && !waitHandle.WaitOne(0))
                        {
                            if (!sawfiles && location.GetFiles().Length > 0)
                            {
                                sawfiles = true;
                            }
                            Thread.Sleep(500);
                        }

                        location.Refresh();
                        Assert.IsTrue(waitHandle.WaitOne(0), "The workflow never completed!");
                        Assert.IsTrue(location.Exists, "Can't find the cache directory - it should have been created!");
                        Assert.IsTrue(location.GetFiles().Length == 0, "Some files were left after the run - they should have been cleaned up!");
                        Assert.IsTrue(sawfiles, "No files ever appeared in that directory - what the heck happened - as if nothing was persisted!");
                    }
                    finally
                    {
                        workflowRuntime.StopRuntime();
                    }
                }
            }
        }

        [TestMethod]
        public void TestCleanup()
        {
            ///
            /// Timers and other things are registered by the file persist service. Make sure it
            /// cleans up after itself. Wait for the full 7 seconds and then go away... :-)
            /// 
            DirectoryInfo location = new DirectoryInfo(".\\bogusCleanup");
            using (ManualResetEvent waitIdle = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    // Start up the workflow...
                    workflowRuntime.AddService(new FilePersistenceService(true, location));

                    workflowRuntime.WorkflowIdled += (o, arg) => waitIdle.Set();
                    workflowRuntime.StartRuntime();

                    WorkflowInstance inst = workflowRuntime.CreateWorkflow(typeof(SimpleWorkflowWithIdle));
                    inst.Start();

                    ///
                    /// Wait for the workflow to enter the idle state.
                    /// 

                    waitIdle.WaitOne();

                    ///
                    /// Ok - now shut down the workflow...
                    /// 

                    workflowRuntime.StopRuntime();
                }
            }

            Thread.Sleep(6 * 1000);
        }

        [TestMethod]
        public void ShutdownPersistence()
        {
            ///
            /// Shut down the runtime, start a new one. See if this works... or not! :-)
            ///

            DirectoryInfo location = new DirectoryInfo(".\\bogusPersistence");
            /// Make sure we spot the running!
            using (ManualResetEvent waitIdle = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    // Start up the workflow...
                    workflowRuntime.AddService(new FilePersistenceService(true, location));

                    workflowRuntime.WorkflowIdled += (o, arg) => waitIdle.Set();
                    workflowRuntime.StartRuntime();

                    WorkflowInstance inst = workflowRuntime.CreateWorkflow(typeof(SimpleWorkflowWithIdle));
                    inst.Start();

                    ///
                    /// Wait for the workflow to enter the idle state.
                    /// 

                    waitIdle.WaitOne();

                    ///
                    /// Ok - now shut down the workflow...
                    /// 

                    workflowRuntime.StopRuntime();
                }
            }

            ///
            /// Make sure there are files in the storage area. If there aren't then this
            /// isn't a good test!
            /// 

            location.Refresh();
            Assert.IsTrue(location.Exists, "Directory for saving stuff isn't here");
            Assert.IsTrue(location.GetFiles().Length > 0, "There are no files saved; did anything get stored!?");

            ///
            /// Put a 1 second pause in here - just to see the magic that the timer keeps running even though
            /// the whole thing is swapped out of memory. :-)
            /// 

            Thread.Sleep(1000);

            ///
            /// Start up the runtime and see if the thing resumes properly...
            /// 

            using (ManualResetEvent waitDone2 = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    try
                    {
                        // Start up the workflow...
                        workflowRuntime.AddService(new FilePersistenceService(true, location));

                        /// Make sure we spot the running!
                        workflowRuntime.WorkflowCompleted += (o, arg) => waitDone2.Set();
                        workflowRuntime.StartRuntime();

                        ///
                        /// Wait for the workflow to enter the idle state.
                        /// 

                        Assert.IsTrue(waitDone2.WaitOne(7000), "The workflow never completed!");
                    }
                    finally
                    {
                        workflowRuntime.StopRuntime();
                    }
                }
            }
        }

        [TestMethod]
        public void TestBogusFiles()
        {
            /// See if another random file left in the directory causes problems when this guy comes back.
            ///
            /// Shut down the runtime, start a new one. See if this works... or not! :-)
            ///

            DirectoryInfo location = new DirectoryInfo(".\\bogusPersistence");
            /// Make sure we spot the running!
            using (ManualResetEvent waitIdle = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    // Start up the workflow...
                    workflowRuntime.AddService(new FilePersistenceService(true, location));

                    workflowRuntime.WorkflowIdled += (o, arg) => waitIdle.Set();
                    workflowRuntime.StartRuntime();

                    WorkflowInstance inst = workflowRuntime.CreateWorkflow(typeof(SimpleWorkflowWithIdle));
                    inst.Start();

                    ///
                    /// Wait for the workflow to enter the idle state.
                    /// 

                    waitIdle.WaitOne();

                    ///
                    /// Ok - now shut down the workflow...
                    /// 

                    workflowRuntime.StopRuntime();
                }
            }

            ///
            /// Create a random guy in the directory and make sure it isn't reloaded for
            /// some reason
            /// 

            location.Refresh();
            using (Stream s = File.Create(location.FullName + "\\location"))
            {
                TextWriter wr = new System.IO.StreamWriter(s);
                wr.Write("hi there");
                wr.Close();
            }

            ///
            /// Put a 1 second pause in here - just to see the magic that the timer keeps running even though
            /// the whole thing is swapped out of memory. :-)
            /// 

            Thread.Sleep(1000);

            ///
            /// Start up the runtime and see if the thing resumes properly...
            /// 

            using (ManualResetEvent waitDone2 = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    try
                    {
                        // Start up the workflow...
                        workflowRuntime.AddService(new FilePersistenceService(true, location));

                        /// Make sure we spot the running!
                        workflowRuntime.WorkflowCompleted += (o, arg) => waitDone2.Set();
                        workflowRuntime.StartRuntime();

                        ///
                        /// Wait for the workflow to enter the idle state.
                        /// 

                        Assert.IsTrue(waitDone2.WaitOne(7000), "The workflow never completed!");
                    }
                    finally
                    {
                        workflowRuntime.StopRuntime();
                    }
                }
            }
        }

        [TestMethod]
        public void TestAbort()
        {
            ///
            /// Run a WF, and then abort the wf. Make sure that the cache directory
            /// has correctly removed the file from there.
            /// 

            DirectoryInfo location = new DirectoryInfo(".\\bogusCleanup");
            using (ManualResetEvent waitIdle = new ManualResetEvent(false))
            {
                using (WorkflowRuntime workflowRuntime = new WorkflowRuntime())
                {
                    // Start up the workflow...
                    workflowRuntime.AddService(new FilePersistenceService(true, location));

                    workflowRuntime.WorkflowIdled += (o, arg) => waitIdle.Set();
                    workflowRuntime.StartRuntime();

                    WorkflowInstance inst = workflowRuntime.CreateWorkflow(typeof(SimpleWorkflowWithIdle));
                    inst.Start();

                    ///
                    /// Wait for the workflow to enter the idle state.
                    /// 

                    waitIdle.WaitOne();

                    ///
                    /// Verify there is actually some data in the output directory! :-)
                    /// 

                    Assert.IsTrue(location.GetFiles().Length != 0, "Expected a cache file for object, but none was found!");

                    ///
                    /// Abort the WF. This is done in a sync way
                    /// 

                    inst.Terminate("Time to Terminate!");

                    Assert.IsTrue(location.GetFiles().Length == 0, "Expecting to find no files in file persistance but somehow they call came off. It couldn't have been me, right?");


                    ///
                    /// Ok - now shut down the workflow...
                    /// 

                    workflowRuntime.StopRuntime();
                }
            }
        }

        [TestMethod]
        public void TestDelayActivityCrash()
        {
            /// Crash the runtime while waiting for the delay activity to complete. Make sure the WF
            /// comes back to life correctly. This is to make sure that the delay activity timers are correctly
            /// dealt with.

            /// Since we are using the delay acivity up above, this is automatically satsified.

            SimpleWorkflowWithIdle idl = new SimpleWorkflowWithIdle();
            Assert.IsTrue(idl.delay.GetType() == typeof(DelayActivity));
        }
    }
}
